home *** CD-ROM | disk | FTP | other *** search
/ Scene Storm / Scene Storm - Volume 1.iso / coding / c / snoopdos_source / settings.c < prev    next >
C/C++ Source or Header  |  1996-02-16  |  52KB  |  1,907 lines

  1. /*
  2.  *        SETTINGS.C                                            vi:ts=4
  3.  *
  4.  *      Copyright (c) Eddy Carroll, September 1994.
  5.  *
  6.  *        This module handles all the command parsing for tooltypes, command
  7.  *        line options, config files, AREXX, etc.
  8.  */        
  9.  
  10. #include "system.h"
  11. #include "snoopdos.h"
  12.  
  13. extern char Version[];            /* From Snoopdos.c */
  14. extern char CommodityTitle[];    /* From Snoopdos.c */
  15.  
  16. char ConfigID[] = "<SnoopDos Settings>";
  17.  
  18. ULONG            UpdateFlags;        /* Shows what settings were changed        */
  19. struct MsgPort *RemoteReplyPort;    /* Used when talking to b/g SnoopDos    */
  20.  
  21. /*
  22.  *        Now the result codes returned by our simple command interpreter
  23.  */
  24. typedef enum {
  25.     EXEC_FAIL,            /* The command failed for some reason    */
  26.     EXEC_OKAY,            /* The command succeeded                */
  27.     EXEC_UNKNOWN,        /* The command wasn't recognised        */
  28.     EXEC_NOPARAM        /* The command was missing a parameter    */
  29. } ExecEnum;
  30.  
  31. /*
  32.  *        Now let's define the commands we understand.
  33.  */
  34. #define CMD_UNKNOWN        -1
  35. #define CMD_NOPARAM        -2
  36.  
  37. typedef enum {
  38.     CMD_END,
  39.  
  40.     /*
  41.      *        Options within function requester. Note that these MUST correspond
  42.      *        exactly with the first set of enums in SNOOPDOS.H for GID_???!
  43.      */
  44.     CMD_FINDPORT,
  45.     CMD_FINDRESIDENT,
  46.     CMD_FINDSEMAPHORE,
  47.     CMD_FINDTASK,
  48.     CMD_LOCKSCREEN,
  49.     CMD_OPENDEVICE,
  50.     CMD_OPENFONT,
  51.     CMD_OPENLIBRARY,
  52.     CMD_OPENRESOURCE,
  53.     CMD_READTOOLTYPES,
  54.     CMD_SENDREXX,
  55.  
  56.     CMD_CHANGEDIR,
  57.     CMD_DELETE,
  58.     CMD_EXECUTE,
  59.     CMD_GETVAR,
  60.     CMD_LOADSEG,
  61.     CMD_LOCK,
  62.     CMD_MAKEDIR,
  63.     CMD_MAKELINK,
  64.     CMD_OPEN,
  65.       CMD_RENAME,
  66.       CMD_RUNCOMMAND,
  67.       CMD_SETVAR,
  68.     CMD_DOSSYSTEM,        /* CMD_SYSTEM is defined in dos/dosextens.h    */
  69.  
  70.     CMD_DUMMY1,
  71.     CMD_DUMMY2,
  72.     CMD_DUMMY3,
  73.     CMD_DUMMY4,
  74.     CMD_DUMMY5,
  75.  
  76.     CMD_ONLYSHOWFAILS,
  77.     CMD_SHOWCLI,
  78.     CMD_SHOWFULLPATH,
  79.     CMD_USEDEVICENAME,
  80.     CMD_MONITORPACKETS,
  81.     CMD_MONALLPACKETS,
  82.     CMD_MONROMCALLS,
  83.     CMD_IGNORESHELL,
  84.  
  85. #define MAX_BOOL_CMD            CMD_IGNORESHELL
  86.  
  87.     CMD_MATCHNAME,
  88.  
  89.     /*
  90.      *        General commands
  91.      */
  92.     CMD_LOADSETTINGS,
  93.     CMD_SAVESETTINGS,
  94.     CMD_LOADDEFSETTINGS,
  95.     CMD_SAVEDEFSETTINGS,
  96.     CMD_SETTINGS,
  97.     CMD_FUNCTIONS,
  98.     CMD_LANGUAGE,
  99.     CMD_CLEARBUFFER,
  100.     CMD_WINDOWWIDTH,
  101.     CMD_HELP,
  102.     CMD_COPYWINDOW,
  103.     CMD_COPYBUFFER,
  104.     CMD_SAVEWINDOW,
  105.     CMD_SAVEBUFFER,
  106.     CMD_SHOW,
  107.     CMD_HIDE,
  108.     CMD_OPENFORMAT,
  109.     CMD_OPENFUNCTION,
  110.     CMD_OPENSETUP,
  111.     CMD_CLOSEFORMAT,
  112.     CMD_CLOSEFUNCTION,
  113.     CMD_CLOSESETUP,
  114.     CMD_QUIT,
  115.     CMD_PAUSE,
  116.     CMD_UNPAUSE,
  117.     CMD_DISABLE,
  118.     CMD_ENABLE,
  119.     CMD_SINGLESTEP,
  120.     CMD_OPENLOG,
  121.     CMD_APPENDLOG,
  122.     CMD_OPENSERIALLOG,
  123.     CMD_CLOSELOG,
  124.     CMD_ADDLOG,
  125.     CMD_FLUSHLOG,
  126.     CMD_SCROLLUP,
  127.     CMD_SCROLLDOWN,
  128.     CMD_GOTO,
  129.  
  130.     /*
  131.      *        General settings
  132.      */
  133.     CMD_PATCHRAMLIB,
  134.     CMD_STACKLIMIT,
  135.     CMD_ICONPOS,
  136.     CMD_SHOWGADGETS,
  137.     CMD_HIDEGADGETS,
  138.     CMD_AUTOOPEN,
  139.     CMD_DISABLEWHENHIDDEN,
  140.     CMD_SHOWSTATUS,
  141.     CMD_HIDESTATUS,
  142.     CMD_CREATEICONS,
  143.     CMD_TEXTSPACING,
  144.     CMD_SIMPLEREFRESH,
  145.     CMD_SMARTREFRESH,
  146.     CMD_LEFTALIGNED,
  147.     CMD_RIGHTALIGNED,
  148.     CMD_ROWQUALIFIER,
  149.     CMD_MAINPOS,
  150.     CMD_MAINSIZE,
  151.     CMD_FUNCPOS,
  152.     CMD_FORMPOS,
  153.     CMD_SETPOS,
  154.     CMD_TASKPRI,
  155.     CMD_CXPRI,
  156.  
  157.     /*
  158.      *        Options within setup requester
  159.      */
  160.     CMD_HIDEMETHOD,
  161.     CMD_SCREENTYPE,
  162.     CMD_BUFFERSIZE,
  163.     CMD_LOGMODE,
  164.     CMD_FILEIOTYPE,
  165.     CMD_FORMAT,
  166.     CMD_LOGFORMAT,
  167.     CMD_HOTKEY,
  168.     CMD_SCREENNAME,
  169.     CMD_LOGNAME,
  170.     CMD_WINDOWFONT,
  171.     CMD_BUFFERFONT,
  172.  
  173.     NUMCOMMANDS
  174.  
  175. } COMMAND_ID;
  176.  
  177.  
  178. /*
  179.  *        Now associate a command string with each of these identifiers
  180.  */
  181. struct Command {
  182.     short    cmdid;            /* Command ID                            */
  183.     short    changemask;        /* Which group of settings will change    */
  184.     short    numparms;        /* Min number of parameters (0 or more)    */
  185.     char    *name;            /* Command name                            */
  186. } CommandTable[] = {
  187.     /*
  188.      *        In alphabetical order, for quick reference
  189.      */
  190.     CMD_ADDLOG,                SET_NONE,    1, "AddLog",
  191.     CMD_APPENDLOG,            SET_NONE,    1, "AppendLog",
  192.     CMD_AUTOOPEN,            SET_MAIN,    0, "AutoOpen",
  193.     CMD_BUFFERFONT,         SET_SETUP,     1, "BufferFont",
  194.     CMD_BUFFERSIZE,         SET_SETUP,     1, "BufferSize",
  195.     CMD_CHANGEDIR,            SET_FUNC,    0, "ChangeDir",
  196.     CMD_CLEARBUFFER,        SET_FUNC,    0, "ClearBuffer",
  197.     CMD_CLOSEFORMAT,        SET_NONE,    0, "CloseFormat",
  198.     CMD_CLOSEFUNCTION,        SET_NONE,    0, "CloseFunction",
  199.     CMD_CLOSELOG,            SET_NONE,    0, "CloseLog",
  200.     CMD_CLOSESETUP,         SET_NONE,    0, "CloseSetup",
  201.     CMD_COPYBUFFER,         SET_NONE,    0, "CopyBuffer",
  202.     CMD_COPYWINDOW,         SET_NONE,    0, "CopyWindow",
  203.     CMD_CREATEICONS,        SET_MAIN,    0, "CreateIcons",
  204.     CMD_HOTKEY,                SET_SETUP,    1, "CX_PopKey",
  205.     CMD_SHOW,                SET_NONE,    0, "CX_Popup",
  206.     CMD_CXPRI,                SET_NONE,    1, "CX_Priority",
  207.     CMD_DELETE,             SET_FUNC,    0, "Delete",
  208.     CMD_DISABLE,            SET_NONE,    0, "Disable",
  209.     CMD_DISABLEWHENHIDDEN,    SET_MAIN,    0, "DisableWhenHidden",
  210.     CMD_ENABLE,             SET_NONE,    0, "Enable",
  211.     CMD_EXECUTE,            SET_FUNC,    0, "Execute",
  212.     CMD_FILEIOTYPE,         SET_SETUP,    1, "FileIOType",
  213.     CMD_FINDPORT,            SET_FUNC,    0, "FindPort",
  214.     CMD_FINDRESIDENT,        SET_FUNC,    0, "FindResident",
  215.     CMD_FINDSEMAPHORE,        SET_FUNC,    0, "FindSemaphore",
  216.     CMD_FINDTASK,            SET_FUNC,    0, "FindTask",
  217.     CMD_FLUSHLOG,            SET_NONE,    0, "FlushLog",
  218.     CMD_FORMAT,             SET_SETUP,    1, "Format",
  219.     CMD_FORMPOS,            SET_MAIN,    1, "FormatWindowPos",
  220.     CMD_FUNCTIONS,            SET_FUNC,    1, "Functions",
  221.     CMD_FUNCPOS,            SET_MAIN,    1, "FunctionWindowPos",
  222.     CMD_GETVAR,             SET_FUNC,    0, "GetVar",
  223.     CMD_GOTO,                SET_NONE,    1, "GotoLine",
  224.     CMD_HELP,                SET_NONE,    0, "Help",
  225.     CMD_HIDE,                SET_NONE,    0, "Hide",
  226.     CMD_HIDEGADGETS,        SET_MAIN,    0, "HideGadgets",
  227.     CMD_HIDEMETHOD,         SET_SETUP,    1, "HideMethod",
  228.     CMD_HIDESTATUS,         SET_MAIN,    0, "HideStatus",
  229.     CMD_HOTKEY,             SET_SETUP,    1, "HotKey",
  230.     CMD_ICONPOS,            SET_MAIN,    1, "IconPos",
  231.     CMD_IGNORESHELL,        SET_FUNC,    0, "IgnoreShell",
  232.     CMD_LANGUAGE,            SET_NONE,    1, "Language",
  233.     CMD_LEFTALIGNED,        SET_MAIN,    0, "LeftAligned",
  234.     CMD_LOADDEFSETTINGS,    SET_NONE,    0, "LoadDefSettings",
  235.     CMD_LOADSEG,            SET_FUNC,    0, "LoadSeg",
  236.     CMD_LOADSETTINGS,         SET_NONE,    1, "LoadSettings",
  237.     CMD_LOCK,                SET_FUNC,    0, "Lock",
  238.     CMD_LOCKSCREEN,         SET_FUNC,    0, "LockScreen",
  239.     CMD_LOGFORMAT,            SET_SETUP,    1, "LogFormat",
  240.     CMD_LOGMODE,            SET_SETUP,    1, "LogMode",
  241.     CMD_LOGNAME,            SET_SETUP,    1, "LogName",
  242.     CMD_MAINPOS,            SET_MAIN,    1, "MainWindowPos",
  243.     CMD_MAINSIZE,            SET_MAIN,    1, "MainWindowSize",
  244.     CMD_MAKEDIR,            SET_FUNC,    0, "MakeDir",
  245.     CMD_MAKELINK,            SET_FUNC,    0, "MakeLink",
  246.     CMD_MATCHNAME,            SET_FUNC,    1, "MatchName",
  247.     CMD_MONITORPACKETS,     SET_FUNC,    0, "MonitorPackets",
  248.     CMD_MONROMCALLS,        SET_FUNC,    0, "MonitorROMCalls",
  249.     CMD_ONLYSHOWFAILS,        SET_FUNC,    0, "OnlyShowFails",
  250.     CMD_OPEN,                SET_FUNC,    0, "Open",
  251.     CMD_OPENDEVICE,         SET_FUNC,    0, "OpenDevice",
  252.     CMD_OPENFONT,            SET_FUNC,    0, "OpenFont",
  253.     CMD_OPENFORMAT,         SET_NONE,    0, "OpenFormat",
  254.     CMD_OPENFUNCTION,        SET_NONE,    0, "OpenFunction",
  255.     CMD_OPENLIBRARY,        SET_FUNC,    0, "OpenLibrary",
  256.     CMD_OPENLOG,            SET_NONE,    1, "OpenLog",
  257.     CMD_OPENRESOURCE,        SET_FUNC,    0, "OpenResource",
  258.     CMD_OPENSERIALLOG,        SET_NONE,    0, "OpenSerialLog",
  259.     CMD_OPENSETUP,            SET_NONE,    0, "OpenSetup",
  260.     CMD_MONALLPACKETS,        SET_FUNC,    0, "PacketDebugger",
  261.     CMD_PATCHRAMLIB,        SET_NONE,    0, "PatchRamLib",
  262.     CMD_PAUSE,                SET_NONE,    0, "Pause",
  263.     CMD_QUIT,                SET_NONE,    0, "Quit",
  264.     CMD_READTOOLTYPES,        SET_FUNC,    0, "ReadToolTypes",
  265.     CMD_RENAME,             SET_FUNC,    0, "Rename",
  266.     CMD_RIGHTALIGNED,        SET_MAIN,    0, "RightAligned",
  267.     CMD_ROWQUALIFIER,        SET_MAIN,    1, "RowQualifier",
  268.     CMD_RUNCOMMAND,         SET_FUNC,    0, "RunCommand",
  269.     CMD_SAVEBUFFER,         SET_NONE,    1, "SaveBuffer",
  270.     CMD_SAVEDEFSETTINGS,      SET_NONE,    0, "SaveDefSettings",
  271.     CMD_SAVESETTINGS,         SET_NONE,    1, "SaveSettings",
  272.     CMD_SAVEWINDOW,         SET_NONE,    1, "SaveWindow",
  273.     CMD_SCREENNAME,         SET_SETUP,    1, "ScreenName",
  274.     CMD_SCREENTYPE,         SET_SETUP,    1, "ScreenType",
  275.     CMD_SCROLLDOWN,            SET_NONE,    1, "ScrollDown",
  276.     CMD_SCROLLUP,            SET_NONE,    1, "ScrollUp",
  277.     CMD_SENDREXX,            SET_FUNC,    0, "SendRexx",
  278.     CMD_SETTINGS,            SET_NONE,    1, "Settings",
  279.     CMD_SETPOS,             SET_MAIN,    1, "SetupWindowPos",
  280.     CMD_SETVAR,             SET_FUNC,    0, "SetVar",
  281.     CMD_SHOW,                SET_NONE,    0, "Show",
  282.     CMD_SHOWCLI,            SET_FUNC,    0, "ShowCLI",
  283.     CMD_SHOWFULLPATH,        SET_FUNC,    0, "ShowFullPath",
  284.     CMD_SHOWGADGETS,        SET_MAIN,    0, "ShowGadgets",
  285.     CMD_SHOWSTATUS,         SET_MAIN,    0, "ShowStatus",
  286.     CMD_SIMPLEREFRESH,        SET_MAIN,    0, "SimpleRefresh",
  287.     CMD_SINGLESTEP,            SET_NONE,    0, "SingleStep",
  288.     CMD_SMARTREFRESH,        SET_MAIN,    0, "SmartRefresh",
  289.     CMD_STACKLIMIT,            SET_MAIN,    1, "StackLimit",
  290.     CMD_DOSSYSTEM,            SET_FUNC,    0, "System",
  291.     CMD_TASKPRI,            SET_NONE,    1, "TaskPri",
  292.     CMD_TEXTSPACING,        SET_MAIN,    1, "TextSpacing",
  293.     CMD_UNPAUSE,            SET_NONE,    0, "Unpause",
  294.     CMD_USEDEVICENAME,        SET_FUNC,    0, "UseDeviceNames",
  295.     CMD_WINDOWFONT,         SET_SETUP,    1, "WindowFont",
  296.     CMD_WINDOWWIDTH,        SET_NONE,    1, "WindowWidth",
  297.     CMD_END,                0,            0, NULL
  298. };
  299.  
  300. #define NUM_CMDNAMES    (sizeof(CommandTable) / sizeof(CommandTable[0]))
  301.  
  302. char *CmdNames[NUMCOMMANDS];    /* Map command IDs back to name strings    */
  303.  
  304. char *Names_HideMethod[] = { "Invisible", "Iconify",    "ToolsMenu",
  305.                              "None",       NULL };
  306. char *Names_ScreenType[] = { "Default",   "Front",        "Named",        NULL };
  307. char *Names_LogMode[]     = { "Prompt",      "Append",        "Overwrite",
  308.                              "SerialPort", NULL };
  309. char *Names_FileIOType[] = { "Automatic", "Immediate",    "Buffered",        NULL };
  310.  
  311. char *Names_Functions[]  = { "All", "None", "AllDos", "NoDos",
  312.                              "AllSystem", "NoSystem", NULL };
  313.  
  314. char *Names_RowQualifier[] = { "Ignore", "None", "Shift", "Alt", "Ctrl",
  315.                                "All",     NULL };
  316.  
  317. typedef enum {
  318.     FUNC_ALL, FUNC_NONE, FUNC_ALLDOS, FUNC_NODOS,
  319.     FUNC_ALLSYSTEM, FUNC_NOSYSTEM
  320. } FuncTypes;
  321.  
  322. /*
  323.  *        InitSettings()
  324.  *
  325.  *        Initialises variables associated with settings. For now, this
  326.  *        just means the mapping array that maps command IDs to command
  327.  *        names. This makes it easier to write out the configuration file.
  328.  */
  329. void InitSettings(void)
  330. {
  331.     struct Command *cmd;
  332.     int i;
  333.  
  334.     for (i = 0; i < NUMCOMMANDS; i++)
  335.         CmdNames[i] = "";    /* Make sure non-cmds initialised to safe value */
  336.  
  337.     for (cmd = CommandTable; cmd->cmdid != CMD_END; cmd++)
  338.         CmdNames[cmd->cmdid] = cmd->name; 
  339. }
  340.  
  341. /*
  342.  *        MatchParam(&var, param, keywords)
  343.  *
  344.  *        Searches the keyword list for a match with param and stores
  345.  *        the result in the given variable. If no match is found, var
  346.  *        is not altered and returns EXEC_FAIL, else returns EXEC_OKAY.
  347.  */
  348. int MatchParam(unsigned char *var, char *param, char **keywords)
  349. {
  350.     int i;
  351.  
  352.     for (i = 0; keywords[i]; i++) {
  353.         if (stricmp(param, keywords[i]) == 0) {
  354.             *var = i;
  355.             return (EXEC_OKAY);
  356.         }
  357.     }
  358.     return (EXEC_FAIL);
  359. }
  360.  
  361. /*
  362.  *        ParseFontName(fontspec, fontname, &fontsize)
  363.  *
  364.  *        Parses the font spec in fontspec, which is of the form
  365.  *        "fontname size" or "fontname.font size" or "fontname.size",
  366.  *        into two parts.
  367.  *
  368.  *        The bulk of the name (plus a .font suffix) is copied into fontname.
  369.  *        The size of the font is copied into fontsize. In the event of a parse
  370.  *        error, EXEC_FAIL is returned and no alteration is made to fontname
  371.  *        or fontsize. For success, EXEC_OKAY is returned.
  372.  *
  373.  *        Note that the contents of the string pointed to by fontspec may be
  374.  *        altered. If fontspec is "default" then a fontsize of 0 is returned
  375.  *        to indicate that SnoopDos should use the system default fonts.
  376.  */
  377. int ParseFontName(char *fontspec, char *fontname, USHORT *fontsize)
  378. {
  379.     char *p;
  380.     int size;
  381.  
  382.     /*
  383.      *        First, see if we can find a dot specifier. Anything before
  384.      *        the dot is a font name.
  385.      */
  386.     if (stricmp(fontspec, "default") == 0) {
  387.         strcpy(fontname, fontspec);
  388.         *fontsize = 0;
  389.         return (EXEC_OKAY);
  390.     }
  391.     p = strchr(fontspec, '.');
  392.     if (p) {
  393.         *p++ = '\0';
  394.         if (strnicmp(p, "font", 4) == 0)
  395.             p += 4;
  396.     } else {
  397.         p = strchr(fontspec, ' ');
  398.         if (!p)
  399.             return (EXEC_FAIL);
  400.         *p++ = '\0';
  401.     }
  402.     while (*p == ' ' || *p == '.')
  403.         p++;
  404.     size = atoi(p);
  405.     if (size == 0)
  406.         return (EXEC_FAIL);
  407.     
  408.     strcpy(fontname, fontspec);
  409.     strcat(fontname, ".font");
  410.     *fontsize = size;
  411.     return (EXEC_OKAY);
  412. }
  413.  
  414. /*
  415.  *        ParseTwoNums(param, &num1, &num2)
  416.  *
  417.  *        Parses the given param string, assumed to be in the form "x1,x2"
  418.  *        and stores the two numbers in the given variables. If either number
  419.  *        is invalid, then no change is made to either number and EXEC_FAIL
  420.  *        is returned, else EXEC_OKAY is returned.
  421.  *
  422.  *        The string pointed to by param may be altered.
  423.  */
  424. int ParseTwoNums(char *param, WORD *num1, WORD *num2)
  425. {
  426.     char *p;
  427.  
  428.     p = strchr(param, ',');
  429.     if (!p)
  430.         return (EXEC_FAIL);
  431.     *p++ = '\0';
  432.  
  433.     while (*p == ' ')
  434.         p++;
  435.     
  436.     if (*param < '-' || *param > '9' || *p < '-' || *p > '9')
  437.         return (EXEC_FAIL);
  438.     
  439.     *num1 = atoi(param);
  440.     *num2 = atoi(p);
  441.     return (EXEC_OKAY);
  442. }
  443.  
  444. /*
  445.  *        cid = ParseCommand(cmdline, cmdname, param, &boolvalue, &cmd)
  446.  *
  447.  *        Copies the cmdline into two separate strings, one for the
  448.  *        command name and one for the parameters. Bool is initalised
  449.  *        to 0 or 1, according to the default value of the parameter
  450.  *        (1 if Yes,True,On, 0 if No, False, Off, or if the command
  451.  *        is prefixed by the word No).
  452.  *
  453.  *        cmd points to the command structure for this command.
  454.  *
  455.  *        cid is the command ID that matches the command, CMD_END for
  456.  *        a null command, CMD_UNKNOWN for an unrecognised command,
  457.  *        and CMD_NOPARAM for a known command with too few parameters.
  458.  *        If CMD_NOPARAM is returned, cmdname and &cmd will be initialised
  459.  *        to the command that was matched.
  460.  *
  461.  */
  462. int ParseCommand(char *cmdline, char *cmdname, char *param, int *boolvalue,
  463.                  struct Command **pcmd)
  464. {
  465.     struct Command *cmd;
  466.     int cid;
  467.     char *p;
  468.     char *q;
  469.  
  470.     if (!cmdline)
  471.         return (CMD_END);
  472.  
  473.     /*
  474.      *        First, copy just the command header
  475.      */
  476.     for (p = cmdline; *p == ' ' || *p == '\t'; p++)
  477.         ;
  478.     q = cmdname;
  479.     while (*p        && *p != ';'  && *p != '='  &&
  480.            *p != ' ' && *p != '\t' && *p != '\n')
  481.         *q++ = *p++;
  482.     *q = '\0';
  483.  
  484.     if (!*cmdname)
  485.         return (CMD_END);    /* Skip over blank lines and comments */
  486.  
  487.     /*
  488.      *        Now skip over any whitespace until we find the next parameter
  489.      */
  490.     while (*p == ' ' || *p == '=' || *p == '\t' || *p == '\n')
  491.         p++;
  492.     q = param;
  493.     if (*p == '\"') {
  494.         /*
  495.          *        Got a quoted string .. copy everything inside the quotes
  496.          */
  497.         p++;
  498.         while (*p && *p != '\n' && *p != '\"')
  499.             *q++ = *p++;
  500.         *q = '\0';
  501.     } else {
  502.         /*
  503.          *        Not a quoted string .. copy everything to end of line
  504.          *        or semicolon, excluding any trailing spaces.
  505.          */
  506.         while (*p && *p != '\n' && *p != ';')
  507.             *q++ = *p++;
  508.         while (--q >= param && (*q == ' ' || *q == '\n' || *q == '\t'))
  509.             ;
  510.         *++q = '\0';
  511.         if (q == param)
  512.             q = NULL;
  513.     }
  514.  
  515.     /*
  516.      *        Finally, if we got no specific parameter, check if the
  517.      *        command beings with "No" -- if so, then assume the
  518.      *        parameter is boolean instead and set accordingly
  519.      */
  520.     *boolvalue = 1;
  521.     if (!q) {
  522.         if (strnicmp(cmdname, "no", 2) == 0) {
  523.             *boolvalue = 0;
  524.             cmdname   += 2;
  525.         }
  526.     } else {
  527.         if (    stricmp(param, "off") == 0    ||
  528.                 stricmp(param, "no")  == 0    ||
  529.                 stricmp(param, "0")   == 0)
  530.         {
  531.             *boolvalue = 0;
  532.         }
  533.     }
  534.  
  535.     /*
  536.      *        Now locate identifier which matches command
  537.      */
  538.     for (cmd = CommandTable; cmd->cmdid != CMD_END; cmd++)
  539.         if (stricmp(cmd->name, cmdname) == 0)
  540.             break;
  541.     
  542.     cid = cmd->cmdid;
  543.     if (cid == CMD_END)
  544.         return (CMD_UNKNOWN);
  545.  
  546.     *pcmd = cmd;
  547.     if (cmd->numparms > 0 && !q)
  548.         return (CMD_NOPARAM);
  549.     
  550.     return (cid);
  551. }
  552.  
  553. /*
  554.  *        ExecCommand(cmd, mode, set)
  555.  *
  556.  *        Interprets the given command and executes it. cmd points to the
  557.  *        command string which is one of the following forms:
  558.  *
  559.  *            command
  560.  *            command=value
  561.  *            setting
  562.  *            nosetting
  563.  *            setting=on
  564.  *            setting=off
  565.  *    
  566.  *        The "setting" commands are used to toggle the various boolean
  567.  *        settings that can be accessed through the requesters.
  568.  *
  569.  *        mode is the place where the setting occurs. This will be one of
  570.  *        MODE_REXX, MODE_SETTINGS, MODE_CMDLINE or MODE_TOOLTYPE, depending
  571.  *        on where the command being executed originated from. In some cases,
  572.  *        this affects how the command is executed.
  573.  *
  574.  *        set is a pointer to a copy of the current settings (NOT the actual
  575.  *        settings!) This copy is updated to reflect the changes. The intention
  576.  *        is that you can call ExecCommand() multiple times with the same
  577.  *        copy, and then finally call InstallSettings() at the end to make
  578.  *        the new settings take effect. This way, only a single update
  579.  *        needs to be done for an entire configuration file.
  580.  *
  581.  *        The global UpdateFlags should be initialised to 0 before the first
  582.  *        call, and then passed to InstallSettings() at the end -- it will
  583.  *        contain the appropriate combination of SET_??? flags to indicate
  584.  *        what settings actually changed.
  585.  *
  586.  *        Returns EXEC_OKAY for success, EXEC_FAIL for failure, or EXEC_UNKNOWN
  587.  *        if the command couldn't be understood.
  588.  */
  589. int ExecCommand(char *cmdline, int mode, Settings *set)
  590. {
  591.     APTR oldwinptr = *TaskWindowPtr;
  592.     struct Command *cmd;        /* Pointer to command                        */
  593.     char cmdname[100];            /* Storage area for command                 */
  594.     char parambuf[100];            /* Storage for parameters                    */
  595.     char *param;                /* Pointer to parameters                    */
  596.     int     boolvalue;                /* for settings: either 1 or 0                */
  597.     int  success = EXEC_OKAY;    /* Default return value                        */
  598.     int  cid;
  599.     int  val;
  600.  
  601.     cid = ParseCommand(cmdline, cmdname, parambuf, &boolvalue, &cmd);
  602.     switch (cid) {
  603.         case CMD_END:        return (EXEC_OKAY);
  604.         case CMD_UNKNOWN:    return (EXEC_UNKNOWN);
  605.         case CMD_NOPARAM:    return (EXEC_NOPARAM);
  606.     }
  607.  
  608.     UpdateFlags |= cmd->changemask;
  609.     param = parambuf;
  610.     
  611.     /*
  612.      *        Okay, got ourselves a valid command. Now interpret it.
  613.      */
  614.     if (cid <= MAX_BOOL_CMD) {
  615.         /*
  616.          *        Got a boolean option to update
  617.          */
  618.         set->Func.Opts[cid] = boolvalue;
  619.         return (EXEC_OKAY);
  620.     }
  621.  
  622.     switch (cid) {
  623.         case CMD_LANGUAGE:
  624.             strcpy(Language, param);
  625.             break;
  626.  
  627.         case CMD_SETTINGS:
  628.             strcpy(DefaultConfigName, param);
  629.             strcpy(ConfigFileName, param);
  630.             break;
  631.  
  632.         case CMD_LOADDEFSETTINGS:
  633.             success = LoadConfig(DefaultConfigName, mode, set);
  634.             break;
  635.  
  636.         case CMD_SAVEDEFSETTINGS:
  637.             success = SaveConfig(DefaultConfigName, SAVE_NOICON);
  638.             break;
  639.  
  640.         case CMD_LOADSETTINGS:
  641.             success = LoadConfig(param, mode, set);
  642.             break;
  643.  
  644.         case CMD_SAVESETTINGS:
  645.             success = SaveConfig(param, SAVE_ICON);
  646.             break;
  647.  
  648.         case CMD_HELP:
  649.         {
  650.             char helpmsg[100];
  651.  
  652.             /*
  653.              *        We install the current settings first, to ensure
  654.              *        that things like the default public screen are
  655.              *        correctly set up before we open help.
  656.              */
  657.             if (UpdateFlags) {
  658.                 InstallSettings(set, UpdateFlags);
  659.                 UpdateFlags = 0;
  660.                 *set = CurSettings;
  661.             }
  662.             if (*param)
  663.                 mysprintf(helpmsg, "LINK %s\n", param);
  664.             else
  665.                 strcpy(helpmsg, MSG(MSG_LINK_MAIN));
  666.             ShowAGuide(helpmsg);
  667.             break;
  668.         }
  669.  
  670.         case CMD_SHOWGADGETS:    set->ShowGadgets   =  boolvalue;    break;
  671.         case CMD_HIDEGADGETS:    set->ShowGadgets   = !boolvalue;    break;
  672.         case CMD_SHOWSTATUS:    set->ShowStatus    =  boolvalue;    break;
  673.         case CMD_HIDESTATUS:    set->ShowStatus       = !boolvalue;    break;
  674.         case CMD_AUTOOPEN:        set->AutoOpenMain  =  boolvalue;    break;
  675.         case CMD_DISABLEWHENHIDDEN: set->DisableWhenHidden = boolvalue; break;
  676.         case CMD_CREATEICONS:    set->MakeIcons     =  boolvalue;    break;
  677.         case CMD_SIMPLEREFRESH:    set->SimpleRefresh =  boolvalue;    break;
  678.         case CMD_SMARTREFRESH:    set->SimpleRefresh = !boolvalue;    break;
  679.         case CMD_LEFTALIGNED:    set->RightAlign    = !boolvalue;    break;
  680.         case CMD_RIGHTALIGNED:    set->RightAlign    =  boolvalue;    break;
  681.         case CMD_TEXTSPACING:    
  682.             val = *param - '0';
  683.             if (val < 0 || val > 2)
  684.                 return (EXEC_FAIL);
  685.             set->TextSpacing = val;
  686.             break;
  687.  
  688.         case CMD_ROWQUALIFIER:
  689.             return MatchParam(&set->RowQualifier, param, Names_RowQualifier);
  690.  
  691.         case CMD_FUNCTIONS:
  692.             /*
  693.              *        Set or clear the function table according to the
  694.              *        parameters
  695.              */
  696.         {
  697.             unsigned char functype;
  698.             int low  = FIRST_SYS_GADGET;
  699.             int high = LAST_DOS_GADGET;
  700.             int bool = 1;
  701.             int i;
  702.  
  703.             if (MatchParam(&functype, param, Names_Functions) == EXEC_FAIL)
  704.                 return (EXEC_FAIL);
  705.  
  706.             switch (functype) {
  707.                 case FUNC_ALL:         break;                /* Use defaults */
  708.                 case FUNC_NONE:         bool = 0; break;
  709.                 case FUNC_ALLDOS:     low  = FIRST_DOS_GADGET;            break;
  710.                 case FUNC_NODOS:     low  = FIRST_DOS_GADGET; bool = 0; break;
  711.                 case FUNC_ALLSYSTEM: high = LAST_SYS_GADGET;            break;
  712.                 case FUNC_NOSYSTEM:     high = LAST_SYS_GADGET;  bool = 0; break;
  713.             }
  714.             for (i = low; i <= high; i++)
  715.                 set->Func.Opts[i] = bool;
  716.             break;
  717.         }
  718.  
  719.         case CMD_COPYWINDOW:
  720.             DisableAllWindows();
  721.             success = SaveBuffer(SAVEBUF_WINDOW, SAVEBUF_CLIPBOARD,
  722.                                  SAVEBUF_OVERWRITE);
  723.             EnableAllWindows();
  724.             break;
  725.                                 /* Fallthrough */
  726.         case CMD_COPYBUFFER:
  727.             DisableAllWindows();
  728.             success = SaveBuffer(SAVEBUF_ALL, SAVEBUF_CLIPBOARD,
  729.                                  SAVEBUF_OVERWRITE);
  730.             EnableAllWindows();
  731.             break;
  732.  
  733.         case CMD_SAVEWINDOW:
  734.             DisableAllWindows();
  735.             success = SaveBuffer(SAVEBUF_WINDOW, param, SAVEBUF_OVERWRITE);
  736.             EnableAllWindows();
  737.             break;
  738.  
  739.         case CMD_SAVEBUFFER:
  740.             DisableAllWindows();
  741.             success = SaveBuffer(SAVEBUF_ALL, param, SAVEBUF_OVERWRITE);
  742.             EnableAllWindows();
  743.             break;
  744.             
  745.         case CMD_CXPRI:
  746.             CommodityPriority = atoi(param);
  747.             if (HotKeyActive) {
  748.                 /*
  749.                  *        Reinstall commodity to take advantage of the
  750.                  *        updated priority
  751.                  */
  752.                 InstallHotKey(CurSettings.Setup.HotKey);
  753.             }
  754.             break;
  755.  
  756.         case CMD_ICONPOS:
  757.             success = ParseTwoNums(param, &set->IconPosLeft, &set->IconPosTop);
  758.             break;
  759.  
  760.         case CMD_HIDE:
  761.         case CMD_SHOW:
  762.             /*
  763.              *        Install all settings modified so far
  764.              */
  765.             if (UpdateFlags) {
  766.                 InstallSettings(set, UpdateFlags);
  767.                 UpdateFlags = 0;
  768.                 *set = CurSettings;
  769.             }
  770.             /*
  771.              *        We allow both of these so that NOSHOW and NOHIDE
  772.              *        will also work, as well as SHOW=YES and HIDE=NO
  773.              *        In particular, CX_Popup=Yes and CX_Popup=No will
  774.              *        work as expected.
  775.              */
  776.             if ((boolvalue && cid == CMD_SHOW) ||
  777.                                         (!boolvalue && cid == CMD_HIDE)) {
  778.                 /*
  779.                  *        Showing SnoopDos. Install all settings changed
  780.                  *        so far, so that they'll be in effect when the window
  781.                  *        is open (especially font changes)
  782.                  */
  783.                 success = ShowSnoopDos();
  784.                 HideOnStartup = 0;
  785.             } else {
  786.                 HideSnoopDos();
  787.                 HideOnStartup = 1;
  788.             }
  789.             break;
  790.  
  791.         case CMD_OPENFORMAT:
  792.         case CMD_OPENFUNCTION:
  793.         case CMD_OPENSETUP:
  794.                 /*
  795.                  *        Install the current settings, so that they take
  796.                  *        effect before the window is opened (font changes
  797.                  *        and the like).
  798.                  */
  799.                 if (UpdateFlags) {
  800.                     InstallSettings(set, UpdateFlags);
  801.                     UpdateFlags = 0;
  802.                     *set = CurSettings;
  803.                 }
  804.                 switch (cid) {
  805.                     case CMD_OPENFORMAT:    success = OpenFormatWindow();
  806.                                             break;
  807.                     case CMD_OPENFUNCTION:    success = OpenFunctionWindow();
  808.                                             break;
  809.                     case CMD_OPENSETUP:        success = OpenSettingsWindow();
  810.                                             break;
  811.                 }
  812.                 break;
  813.  
  814.         case CMD_CLOSEFORMAT:        CloseFormatWindow();            break;
  815.         case CMD_CLOSEFUNCTION:        CloseFunctionWindow();            break;
  816.         case CMD_CLOSESETUP:        CloseSettingsWindow();            break;
  817.  
  818.         case CMD_QUIT:
  819.             if (mode != MODE_SETTINGS)
  820.                 QuitFlag = 1;
  821.             else
  822.                 success = EXEC_FAIL;
  823.             break;
  824.             
  825.         case CMD_SINGLESTEP:        SingleStep();                        break;
  826.  
  827.         case CMD_PAUSE:
  828.         case CMD_DISABLE:
  829.         case CMD_UNPAUSE:
  830.         case CMD_ENABLE:
  831.             /*
  832.              *        We treat these four together so we can account for
  833.              *        all the different boolean verisons (Disable=Yes,
  834.              *        Enable=No, UnPause=Yes, Pause=No, etc.)
  835.              */
  836.             if ((cid == CMD_DISABLE && boolvalue) ||
  837.                 (cid == CMD_ENABLE && !boolvalue))
  838.             {
  839.                 SetMonitorMode(MONITOR_DISABLED);
  840.             } else if ((cid == CMD_PAUSE && boolvalue) ||
  841.                        (cid == CMD_UNPAUSE && !boolvalue))
  842.             {
  843.                 SetMonitorMode(MONITOR_PAUSED);
  844.             } else
  845.                 SetMonitorMode(MONITOR_NORMAL);
  846.             break;
  847.  
  848.         case CMD_OPENLOG:
  849.         case CMD_APPENDLOG:
  850.             /*
  851.              *        For these two, we make any current settings take effect,
  852.              *        so that things like default file buffering mode will be
  853.              *        activated.
  854.              */
  855.             if (UpdateFlags) {
  856.                 InstallSettings(set, UpdateFlags);
  857.                 UpdateFlags = 0;
  858.                 *set = CurSettings;
  859.             }
  860.             if (cid == CMD_OPENLOG)
  861.                 success = OpenLog(LOGMODE_OVERWRITE, param);
  862.             else
  863.                 success = OpenLog(LOGMODE_APPEND, param);
  864.             break;
  865.  
  866.         case CMD_OPENSERIALLOG:
  867.             success = OpenLog(LOGMODE_SERIALPORT, param);
  868.             break;
  869.  
  870.         case CMD_CLOSELOG:
  871.             CloseLog();
  872.             break;
  873.  
  874.         case CMD_ADDLOG:
  875.             /*
  876.              *        Output a user comment to the specified logfile
  877.              */
  878.             strcat(param, "\n");
  879.             WriteLog(param);
  880.             break;
  881.  
  882.         case CMD_FLUSHLOG:
  883.             /*
  884.              *        Flush the current contents of the log
  885.              */
  886.             WriteLog(NULL);
  887.             break;
  888.  
  889.         case CMD_HIDEMETHOD: return MatchParam(&set->Setup.HideMethod,    param,
  890.                                                Names_HideMethod);
  891.         case CMD_SCREENTYPE: return MatchParam(&set->Setup.ScreenType,    param,
  892.                                                Names_ScreenType);
  893.         case CMD_LOGMODE:     return MatchParam(&set->Setup.LogMode,        param,
  894.                                                Names_LogMode);
  895.         case CMD_FILEIOTYPE: return MatchParam(&set->Setup.FileIOType,    param,
  896.                                                Names_FileIOType);
  897.  
  898.         case CMD_BUFFERSIZE:
  899.             val = atoi(param);
  900.             if (val > 1)
  901.                 set->Setup.BufferSize = val;
  902.             break;
  903.  
  904.         case CMD_WINDOWWIDTH:
  905.             SetMainWindowWidth(atoi(param));    /* 0 is supported */
  906.             break;
  907.  
  908.         case CMD_STACKLIMIT:
  909.             if (*param < '0' || *param > '9')
  910.                 return (EXEC_FAIL);
  911.             set->StackLimit = atoi(param);
  912.             break;
  913.  
  914.         case CMD_PATCHRAMLIB:    break;    /* Actually handled in ParseStartup */
  915.  
  916.         case CMD_FORMAT:        strcpy(set->Setup.BufferFormat,  param); break;
  917.         case CMD_LOGFORMAT:
  918.             if (stricmp(param, "none") == 0)
  919.                 *param = '\0';
  920.             strcpy(set->Setup.LogfileFormat, param); break;
  921.             break;
  922.  
  923.         case CMD_HOTKEY:        strcpy(set->Setup.HotKey,          param); break;
  924.         case CMD_SCREENNAME:    strcpy(set->Setup.ScreenName,     param); break;
  925.         case CMD_LOGNAME:        strcpy(set->Setup.LogFile,         param);
  926.                                 *TaskWindowPtr = (APTR)-1;
  927.                                 if (IsFileSystem(set->Setup.LogFile))
  928.                                     strcpy(ChosenLogName, param);
  929.                                 *TaskWindowPtr = oldwinptr;
  930.                                 break;
  931.  
  932.         case CMD_MATCHNAME:      strcpy(set->Func.Pattern,         param); break;
  933.         case CMD_WINDOWFONT:
  934.             return ParseFontName(param, set->Setup.WindowFont,
  935.                                         &set->Setup.WinFontSize);
  936.         case CMD_BUFFERFONT:
  937.             return ParseFontName(param, set->Setup.BufferFont,
  938.                                         &set->Setup.BufFontSize);
  939.  
  940.         case CMD_MAINSIZE:
  941.             success = ParseTwoNums(param, &set->MainWinWidth,
  942.                                           &set->MainWinHeight);
  943.             if (success && mode != MODE_SETTINGS && MainWindow)
  944.                 SizeWindow(MainWindow, set->MainWinWidth - MainWindow->Width,
  945.                                        set->MainWinHeight- MainWindow->Height);
  946.             break;
  947.  
  948.         case CMD_MAINPOS:
  949.             success = ParseTwoNums(param, &set->MainWinLeft, &set->MainWinTop);
  950.             if (success && mode != MODE_SETTINGS && MainWindow)
  951.                 MoveWindow(MainWindow, set->MainWinLeft - MainWindow->LeftEdge,
  952.                                        set->MainWinTop  - MainWindow->TopEdge);
  953.             break;
  954.  
  955.         case CMD_FORMPOS:
  956.             success = ParseTwoNums(param, &set->FormWinLeft, &set->FormWinTop);
  957.             if (success && mode != MODE_SETTINGS && FormWindow)
  958.                 MoveWindow(FormWindow, set->FormWinLeft - FormWindow->LeftEdge,
  959.                                        set->FormWinTop  - FormWindow->TopEdge);
  960.             break;
  961.  
  962.         case CMD_FUNCPOS:
  963.             success = ParseTwoNums(param, &set->FuncWinLeft, &set->FuncWinTop);
  964.             if (success && mode != MODE_SETTINGS && FuncWindow)
  965.                 MoveWindow(FuncWindow, set->FuncWinLeft - FuncWindow->LeftEdge,
  966.                                        set->FuncWinTop  - FuncWindow->TopEdge);
  967.             break;
  968.  
  969.         case CMD_SETPOS:
  970.             success = ParseTwoNums(param, &set->SetupWinLeft,
  971.                                           &set->SetupWinTop);
  972.             if (success && mode != MODE_SETTINGS && SetWindow)
  973.                 MoveWindow(SetWindow, set->SetupWinLeft - SetWindow->LeftEdge,
  974.                                       set->SetupWinTop  - SetWindow->TopEdge);
  975.             break;
  976.  
  977.         case CMD_TASKPRI:
  978.             val = atoi(param);
  979.             if ((val == 0 && *param != '0') || val < -20 || val > 20)
  980.                 return (EXEC_FAIL);
  981.             SetTaskPri(SysBase->ThisTask, val);
  982.             if (MainWindow)
  983.                 SetMenuOptions();
  984.             break;
  985.  
  986.         case CMD_CLEARBUFFER:
  987.             ClearWindowBuffer();
  988.             break;
  989.  
  990.         case CMD_GOTO:
  991.             val = atoi(param);
  992.             if (val != 0) {
  993.                 val += BaseSeq;        /* Get real start position */
  994.                 if (val > TopSeq)
  995.                     DoArrowScrolling(GID_DOWNARROW, val - TopSeq);
  996.                 else
  997.                     DoArrowScrolling(GID_UPARROW, TopSeq - val);
  998.             } else
  999.                 success = EXEC_FAIL;
  1000.             break;
  1001.  
  1002.         case CMD_SCROLLUP:
  1003.         case CMD_SCROLLDOWN:
  1004.             val = atoi(param);
  1005.             if (!val)
  1006.                 val = 1;
  1007.             if (cid == CMD_SCROLLUP)
  1008.                 DoArrowScrolling(GID_UPARROW, val);
  1009.             else
  1010.                 DoArrowScrolling(GID_DOWNARROW, val);
  1011.             break;
  1012.     }
  1013.     return (success ? EXEC_OKAY : EXEC_FAIL);
  1014. }
  1015.  
  1016. /*
  1017.  *        GetFontDesc(fontdesc, fontname, size)
  1018.  *
  1019.  *        Builds a a string from the supplied fontname and size and stores
  1020.  *        it in fontdesc. Returns a pointer to the new string.
  1021.  *
  1022.  *        For example, name="courier.font" and size=13 will return the
  1023.  *        string "courier 13";
  1024.  *
  1025.  *        In the event that the fontname is invalid, the string "Default"
  1026.  *        is returned instead.
  1027.  */
  1028. char *GetFontDesc(char *fontdesc, char *fontname, int size)
  1029. {
  1030.     char *p;
  1031.  
  1032.     if (!fontname || !*fontname)
  1033.         return ("Default");
  1034.  
  1035.     strcpy(fontdesc, fontname);
  1036.     p = strchr(fontdesc, '.');
  1037.     if (!p)
  1038.         p = fontdesc + strlen(fontdesc);
  1039.     
  1040.     mysprintf(p, " %ld", size);
  1041.     return (fontdesc);
  1042. }
  1043.  
  1044. /*
  1045.  *        SaveConfig(filename, saveicon)
  1046.  *
  1047.  *        Writes the current configuration to the named disk file. Returns
  1048.  *        1 for success, 0 for failure.
  1049.  *
  1050.  *        saveicon is SAVE_ICON if an icon should be saved and CreateIcos
  1051.  *        is true, or SAVE_NOICON if an icon should never be saved.
  1052.  */
  1053. int SaveConfig(char *filename, int saveicon)
  1054. {
  1055.     char tempdesc[MAX_SHORT_LEN];
  1056.     SetupSettings *setup = &CurSettings.Setup;
  1057.     BPTR file;
  1058.     int i;
  1059.  
  1060.     mysprintf(StatusLineText, MSG(MSG_STATUS_SAVESET), filename);
  1061.     ShowStatus(StatusLineText);
  1062.  
  1063.     DisableAllWindows();
  1064.     RecordWindowSizes();
  1065.     file = Open(filename, MODE_NEWFILE);
  1066.     if (!file) {
  1067.         EnableAllWindows();
  1068.         UpdateStatus();
  1069.         return (0);
  1070.     }
  1071.     FPrintf(file, "%s\n;\n;    %s\n;\n;    Settings file\n;\n",
  1072.             ConfigID, Version);
  1073.  
  1074. #define NM(x)            CmdNames[CMD_##x]
  1075. #define PF1(s,p)        FPrintf(file, s, p)
  1076. #define PF2(s,p1,p2)    FPrintf(file, s, p1, p2)
  1077.  
  1078.     /*
  1079.      *        First of all, write out the function settings
  1080.      */
  1081.     for (i = 1; i <= MAX_BOOL_CMD; i++) {
  1082.         if (*CmdNames[i]) {
  1083.             if (CurSettings.Func.Opts[i])
  1084.                 PF1("%s\n",    CmdNames[i]);
  1085.             else
  1086.                 PF1("No%s\n", CmdNames[i]);
  1087.         }
  1088.     }
  1089.     /*
  1090.      *        Now write out all the variable settings
  1091.      */
  1092.     PF2(";\n%s=\"%s\"\n",NM(MATCHNAME),    CurSettings.Func.Pattern);
  1093.     PF2("%s=%s\n",         NM(HIDEMETHOD), Names_HideMethod[setup->HideMethod]);
  1094.     PF2("%s=%s\n",         NM(SCREENTYPE), Names_ScreenType[setup->ScreenType]);
  1095.     PF2("%s=%s\n",         NM(LOGMODE),      Names_LogMode[setup->LogMode]);
  1096.     PF2("%s=%s\n",         NM(FILEIOTYPE), Names_FileIOType[setup->FileIOType]);
  1097.     PF2("%s=%ld\n",         NM(BUFFERSIZE), setup->BufferSize);
  1098.     PF2("%s=\"%s\"\n",    NM(HOTKEY),          setup->HotKey);
  1099.     PF2("%s=\"%s\"\n",    NM(SCREENNAME), setup->ScreenName);
  1100.     PF2("%s=\"%s\"\n",    NM(LOGNAME),    setup->LogFile);
  1101.     PF2("%s=\"%s\"\n",    NM(WINDOWFONT), GetFontDesc(tempdesc,
  1102.                                                     setup->WindowFont,
  1103.                                                      setup->WinFontSize));
  1104.     PF2("%s=\"%s\"\n",    NM(BUFFERFONT), GetFontDesc(tempdesc,
  1105.                                                     setup->BufferFont,
  1106.                                                      setup->BufFontSize));
  1107.     PF2("%s=\"%s\"\n",    NM(FORMAT),     setup->BufferFormat);
  1108.     PF2("%s=\"%s\"\n",    NM(LOGFORMAT),  setup->LogfileFormat);
  1109.  
  1110.     PF2("%s=%ld\n",        NM(TEXTSPACING), CurSettings.TextSpacing);
  1111.  
  1112.     PF1("%s\n",             CurSettings.SimpleRefresh ? NM(SIMPLEREFRESH) :
  1113.                                                     NM(SMARTREFRESH));
  1114.     PF1("%s\n",             CurSettings.RightAlign    ? NM(RIGHTALIGNED) :
  1115.                                                     NM(LEFTALIGNED));
  1116.     PF2("%s=%s\n",      NM(ROWQUALIFIER), Names_RowQualifier[RowQual]);
  1117.     PF1("%s\n",             CurSettings.ShowStatus    ? NM(SHOWSTATUS)      :
  1118.                                                     NM(HIDESTATUS));
  1119.     PF1("%s\n",             CurSettings.ShowGadgets   ? NM(SHOWGADGETS)   :
  1120.                                                     NM(HIDEGADGETS));
  1121.     PF2("%s%s\n",        (AutoOpen ? "" : "No"), NM(AUTOOPEN));
  1122.     PF2("%s%s\n",       (DisableOnHide ? "" : "No"), NM(DISABLEWHENHIDDEN));
  1123.     PF2("%s%s\n",        (CurSettings.MakeIcons ? "" : "No"), NM(CREATEICONS));
  1124.     
  1125.     FPrintf(file, "%s=%ld,%ld\n", NM(MAINPOS),    CurSettings.MainWinLeft,
  1126.                                                   CurSettings.MainWinTop);
  1127.     FPrintf(file, "%s=%ld,%ld\n", NM(MAINSIZE),    CurSettings.MainWinWidth,
  1128.                                                   CurSettings.MainWinHeight);
  1129.     FPrintf(file, "%s=%ld,%ld\n", NM(FORMPOS),    CurSettings.FormWinLeft,
  1130.                                                   CurSettings.FormWinTop);
  1131.     FPrintf(file, "%s=%ld,%ld\n", NM(FUNCPOS),    CurSettings.FuncWinLeft,
  1132.                                                   CurSettings.FuncWinTop);
  1133.     FPrintf(file, "%s=%ld,%ld\n", NM(SETPOS),    CurSettings.SetupWinLeft,
  1134.                                                   CurSettings.SetupWinTop);
  1135.     FPrintf(file, "%s=%ld,%ld\n", NM(ICONPOS),  CurSettings.IconPosLeft,
  1136.                                                 CurSettings.IconPosTop);
  1137.     FPrintf(file, "%s=%ld\n",     NM(STACKLIMIT), CurSettings.StackLimit);
  1138.     FPrintf(file, "%s=%ld\n",     NM(TASKPRI),
  1139.                                   SysBase->ThisTask->tc_Node.ln_Pri);
  1140.     Close(file);
  1141.     if (CreateIcons && saveicon != SAVE_NOICON)
  1142.         WriteIcon(filename);
  1143.     EnableAllWindows();
  1144.     UpdateStatus();
  1145.     GotLastSaved = 1;        /* Indicate "Last Saved" can now be performed */
  1146.     return (1);
  1147. }
  1148.  
  1149. /*
  1150.  *        LoadConfig(filename, mode, set)
  1151.  *
  1152.  *        Attempts to load the specified configuration file into memory.
  1153.  *        Returns 1 for success (having executed all the commands, and updated
  1154.  *        windows etc. as appropriate) or 0 for failure (couldn't open file).
  1155.  *
  1156.  *        To prevent infinite loops, we only allow three levels of nested
  1157.  *        configuration files (i.e. a maximum of three recursive calls to
  1158.  *        LoadConfig)
  1159.  *
  1160.  *        Normally, set is NULL. If non-NULL, then it represents a set
  1161.  *        of settings currently being updated. In this case, LoadConfig
  1162.  *        doesn't actually install the new settings when it's finished
  1163.  *        reading them, it merely updates the values in set with the
  1164.  *        new values and relies on the caller to set them later on.
  1165.  *
  1166.  *        The mode parameter indicates how we are being called -- from
  1167.  *        the CLI, Workbench, ARexx or internally. This is used to determine
  1168.  *        how error messages should be displayed (currently, messages will
  1169.  *        only be displayed in a CLI window).
  1170.  *
  1171.  *        New: we now support reading from an interactive file (CON:....)
  1172.  *        This allows the user to open a command window by trying to load
  1173.  *        a suitable CON: specification. Commands will be executed as soon
  1174.  *        as they arrive, and settings will be updated immediately.
  1175.  */
  1176. int LoadConfig(char *filename, int mode, Settings *set)
  1177. {
  1178.     static int nestcount;
  1179.  
  1180.     Settings newsettings;
  1181.     Settings *myset;
  1182.     int  interactive;
  1183.     int  linenum   = 0;
  1184.     int  retvalue  = EXEC_FAIL;
  1185.     BPTR errorfile = NULL;
  1186.     BPTR file;
  1187.     char linebuf[200];
  1188.  
  1189.     if (set == NULL) {
  1190.         myset          = &newsettings;
  1191.         *myset        = CurSettings;
  1192.         UpdateFlags = 0;
  1193.     } else {
  1194.         myset = set;
  1195.     }
  1196.     if (nestcount >= MAX_LOAD_NESTING)
  1197.         return (EXEC_FAIL);
  1198.     nestcount++;
  1199.     
  1200.     DisableAllWindows();
  1201.     mysprintf(StatusLineText, MSG(MSG_STATUS_LOADSET), filename);
  1202.     ShowStatus(StatusLineText);
  1203.  
  1204.     file = Open(filename, MODE_OLDFILE);
  1205.     if (!file)
  1206.         goto abort_load;
  1207.  
  1208.     /*
  1209.      *        If we're executing this command from a CLI, then display
  1210.      *        error messages in the CLI window, else don't display them
  1211.      *        at all.
  1212.      */
  1213.     if (mode == MODE_CMDLINE)
  1214.         errorfile = Output();
  1215.  
  1216.     interactive = IsInteractive(file);
  1217.     if (interactive) {
  1218.         errorfile = file;    /* Send errors to the command window */
  1219.     } else {
  1220.         /*
  1221.          *        If we're not loading settings from an interactive
  1222.          *        window, then check that the first line of the file
  1223.          *        contains the settings file identifier
  1224.          */
  1225.         if (!FGets(file, linebuf, 199)                            ||
  1226.             strnicmp(linebuf, ConfigID, strlen(ConfigID)) != 0)
  1227.         {
  1228.             goto abort_load;
  1229.         }
  1230.         linenum++;
  1231.     }
  1232.  
  1233.     /*
  1234.      *        Now read in lines from the command file and execute them.
  1235.      */
  1236.     if (interactive) {
  1237.         FPrintf(errorfile, "%s%s", MSG(MSG_CMD_HEADER), MSG(MSG_CMD_PROMPT));
  1238.         Flush(errorfile);
  1239.     }
  1240.     while (FGets(file, linebuf, 199) != NULL) {
  1241.         char *cmdline = linebuf;
  1242.         char *q;
  1243.         int result;
  1244.  
  1245.         linenum++;
  1246.         for (q = cmdline; *q && *q != '\n'; q++)
  1247.             ;
  1248.         if (*q)
  1249.             *q++ = '\0';
  1250.     
  1251.         while (*cmdline == ' ' || *cmdline == '\t')
  1252.             cmdline++;
  1253.  
  1254.         if (!*cmdline || *cmdline == ';')
  1255.             continue;    /* Skip over lines with no text on them */
  1256.  
  1257.         if (stricmp(cmdline, "exit") == 0)    /* Skip rest of file */
  1258.             break;
  1259.  
  1260.         if (interactive && *cmdline == '?') {
  1261.             ShowCommands(errorfile);
  1262.             goto show_prompt;
  1263.         }
  1264.             
  1265.         /*
  1266.          *        Now execute the command ... interactive commands are
  1267.          *        executed internally, to allow QUIT to be executed.
  1268.          */
  1269.         result = ExecCommand(cmdline,
  1270.                              (interactive ? MODE_INTERNAL : MODE_SETTINGS),
  1271.                              myset);
  1272.         if (QuitFlag)
  1273.             break;
  1274.  
  1275.         if (result == EXEC_OKAY) {
  1276.             if (interactive) {
  1277.                 /*
  1278.                  *        For interactive commands, we update the
  1279.                  *        settings at each step along the way so
  1280.                  *        the user can see them taking effect.
  1281.                  */
  1282.                 InstallSettings(myset, UpdateFlags);
  1283.                 UpdateFlags = 0;
  1284.                 *myset = CurSettings;
  1285.             }
  1286.         } else if (errorfile) {
  1287.             int msgid;
  1288.  
  1289.             switch (result) {
  1290.                 case EXEC_UNKNOWN:    msgid = MSG_CMD_UNKNOWN;    break;
  1291.                 case EXEC_FAIL:        msgid = MSG_CMD_FAIL;        break;
  1292.                 case EXEC_NOPARAM:    msgid = MSG_CMD_NOPARAM;    break;
  1293.             }
  1294.             if (!interactive)
  1295.                 FPrintf(errorfile, "%s, line %ld: ", filename, linenum);
  1296.             FPrintf(errorfile, MSG(msgid), cmdline);
  1297.         }
  1298.  
  1299. show_prompt:
  1300.         if (interactive) {
  1301.             FPrintf(errorfile, MSG(MSG_CMD_PROMPT));
  1302.             Flush(errorfile);
  1303.         }
  1304.     }
  1305.     retvalue = EXEC_OKAY;
  1306.  
  1307.     if (interactive) {
  1308.         /*
  1309.          *        For interactive use, we clear any CTRL-C typed by
  1310.          *        the user during usage; this avoids confusion since
  1311.          *        the CTRL-C wouldn't have taken effect immediately
  1312.          *        anyway.
  1313.          */
  1314.         CheckSignal(SIGBREAKF_CTRL_C);
  1315.     }
  1316.     /*
  1317.      *        If we just successfully loaded a file, it was probably the
  1318.      *        defaults file, so enable the "Last Saved" menu option (if it's
  1319.      *        not enabled, then it doesn't try to load a file since there was
  1320.      *        no file ever saved).
  1321.      */
  1322.     GotLastSaved = 1;
  1323.  
  1324. abort_load:
  1325.     if (file)
  1326.         Close(file);
  1327.     nestcount--;
  1328.     if (set == NULL)
  1329.         InstallSettings(myset, UpdateFlags);
  1330.  
  1331.     UpdateStatus();
  1332.     EnableAllWindows();
  1333.     return (retvalue);
  1334. }
  1335.  
  1336. /*
  1337.  *        InitRexxPort
  1338.  *
  1339.  *        Attempts to create SnoopDos's public port and initialise SnoopPort
  1340.  *        and RexxPortMask accordingly. If the port already exists, still
  1341.  *        returns TRUE but SnoopPort will be NULL.
  1342.  *
  1343.  *        If we can't create the port for some reason, returns FALSE.
  1344.  */        
  1345. int InitRexxPort(void)
  1346. {
  1347.     struct MsgPort *port;
  1348.  
  1349.     Forbid();
  1350.     port = FindPort(PORT_NAME);
  1351.     if (!port) {
  1352.         SnoopPort = CreateMsgPort();
  1353.         if (!SnoopPort) {
  1354.             Permit();
  1355.             return (FALSE);
  1356.         }
  1357.         SnoopPort->mp_Node.ln_Name = PORT_NAME;
  1358.         SnoopPort->mp_Node.ln_Pri  = 1;    /* Speed up searches */
  1359.         AddPort(SnoopPort);
  1360.         RexxPortMask = 1 << SnoopPort->mp_SigBit;
  1361.     }
  1362.     Permit();
  1363.     return (TRUE);
  1364. }
  1365.  
  1366. /*
  1367.  *        CleanupRexxPort()
  1368.  *
  1369.  *        Cleans up our SnoopDos port -- removes it from the public port
  1370.  *        list, and then replies to any messages it has outstanding. Call
  1371.  *        before exiting.
  1372.  */
  1373. void CleanupRexxPort(void)
  1374. {
  1375.     if (SnoopPort) {
  1376.         struct RexxMsg *msg;
  1377.  
  1378.         Forbid();
  1379.         RemPort(SnoopPort);
  1380.         while ((msg = (struct RexxMsg *)GetMsg(SnoopPort)) != NULL) {
  1381.             msg->rm_Result1 = RC_FATAL;
  1382.             msg->rm_Result2 = NULL;
  1383.             ReplyMsg(msg);
  1384.         }
  1385.         Permit();
  1386.         DeleteMsgPort(SnoopPort);
  1387.         SnoopPort = NULL;
  1388.     }
  1389.     if (RemoteReplyPort) {
  1390.         DeleteMsgPort(RemoteReplyPort);
  1391.         RemoteReplyPort = NULL;
  1392.     }
  1393. }
  1394.  
  1395. /*
  1396.  *        HandleRexxMsgs()
  1397.  *
  1398.  *        Handles any new messages at our Rexx port
  1399.  */
  1400. void HandleRexxMsgs(void)
  1401. {
  1402.     Settings newsettings = CurSettings;
  1403.     struct RexxMsg *msg;
  1404.  
  1405.     UpdateFlags = 0;
  1406.     while ((msg = (struct RexxMsg *)GetMsg(SnoopPort)) != NULL) {
  1407.         msg->rm_Result1 = RC_OK;
  1408.         msg->rm_Result2 = NULL;
  1409.         if ((msg->rm_Action & RXCODEMASK) == RXCOMM) {
  1410.             /*
  1411.              *        Got a valid ARexx message, now process it
  1412.              */
  1413.             switch (ExecCommand(msg->rm_Args[0], MODE_REXX, &newsettings)) {
  1414.                 /*
  1415.                  *        See include:rexx/errors.h for the meanings of
  1416.                  *        these Rexx return codes
  1417.                  */
  1418.                 case EXEC_NOPARAM:    msg->rm_Result1 = 10; break;
  1419.                 case EXEC_FAIL:        msg->rm_Result1 = 20; break;
  1420.                 case EXEC_UNKNOWN:    msg->rm_Result1 = 30; break;
  1421.             }
  1422.         }
  1423.         ReplyMsg(msg);
  1424.     }
  1425.     InstallSettings(&newsettings, UpdateFlags);
  1426. }
  1427.  
  1428. /*
  1429.  *        SendRemote(cmdline, mode)
  1430.  *
  1431.  *        Sends a command to a remote copy of SnoopDos running in the
  1432.  *        background. The mode is MODE_CMDLINE or MODE_TOOLTYPE. The
  1433.  *        difference is that for MODE_TOOLYPE, HIDE commands are ignored.
  1434.  *
  1435.  *        In both cases, the command is first checked against the command
  1436.  *        table to make sure it's valid. If it's invalid, then if the mode
  1437.  *        is MODE_CMDLINE, an appropriate error message is printed.
  1438.  */
  1439. void SendRemote(char *cmdline, int mode)
  1440. {
  1441.     struct Command *cmd;
  1442.     struct MsgPort *ourport;
  1443.     char cmdname[100];
  1444.     char param[100];
  1445.     int boolvalue;
  1446.     int cid;
  1447.  
  1448.     cid = ParseCommand(cmdline, cmdname, param, &boolvalue, &cmd);
  1449.     switch (cid) {
  1450.         case CMD_UNKNOWN:
  1451.             if (mode == MODE_CMDLINE)
  1452.                 Printf(MSG(MSG_ERROR_CLI_UNKNOWN), cmdline);
  1453.             return;
  1454.  
  1455.         case CMD_NOPARAM:
  1456.             if (mode == MODE_CMDLINE)
  1457.                 Printf(MSG(MSG_ERROR_CLI_NOPARAM), cmdline);
  1458.             return;
  1459.  
  1460.         case CMD_HIDE:
  1461.             /*
  1462.              *        Don't send a HIDE command to the current SnoopDos if
  1463.              *        it was in an icon's tooltypes
  1464.              */
  1465.             if (mode == MODE_TOOLTYPE)
  1466.                 return;
  1467.             break;
  1468.  
  1469.         case CMD_END:
  1470.             return;
  1471.     }
  1472.     
  1473.     /*
  1474.      *        Got a command that's okay to send. Now locate SnoopDos port
  1475.      *        and send it. We have to locate the port each time, in case
  1476.      *        the user quits the background copy suddenly.
  1477.      */
  1478.     if (!RemoteReplyPort) {
  1479.         RemoteReplyPort = CreateMsgPort();
  1480.         if (!RemoteReplyPort)
  1481.             return;
  1482.     }
  1483.     Forbid();
  1484.     ourport = FindPort(PORT_NAME);
  1485.     if (ourport) {
  1486.         struct RexxMsg msg;
  1487.  
  1488.         msg.rm_Action               = RXCOMM;
  1489.         msg.rm_Args[0]             = cmdline;
  1490.         msg.rm_Node.mn_ReplyPort = RemoteReplyPort;
  1491.  
  1492.         PutMsg(ourport, &msg);
  1493.         WaitPort(RemoteReplyPort);
  1494.         GetMsg(RemoteReplyPort);
  1495.         Permit();
  1496.         if (mode == MODE_CMDLINE && msg.rm_Result1 >= RC_ERROR)
  1497.             Printf(MSG(MSG_ERROR_CLI_FAILED), cmdline);
  1498.     } else
  1499.         Permit();
  1500. }
  1501.  
  1502. /*
  1503.  *        ShowCommands(file)
  1504.  *
  1505.  *        Prints a neatly formatted list of recognised commands to
  1506.  *        the specified output file.
  1507.  */
  1508. void ShowCommands(BPTR file)
  1509. {
  1510.     int i;
  1511.     int numrows = (NUM_CMDNAMES + 3) / 4;
  1512.  
  1513.     FPrintf(file, MSG(MSG_CLI_HELPBANNER));
  1514.     for (i = 0; i < numrows; i++) {
  1515.         int j;
  1516.  
  1517.         if (CheckSignal(SIGBREAKF_CTRL_C)) {
  1518.             FPrintf(file, "^C\n");
  1519.             break;
  1520.         }
  1521.         for (j = i; j < NUM_CMDNAMES; j += numrows) {
  1522.             char *pmsg = (CommandTable[j].numparms > 0) ? "*" : " ";
  1523.             char *cmsg = CommandTable[j].name;
  1524.  
  1525.             if (j < (NUM_CMDNAMES - numrows))
  1526.                 FPrintf(file, "%s%-18s", pmsg, cmsg);
  1527.             else
  1528.                 FPrintf(file, "%s%s", pmsg, cmsg);
  1529.         }
  1530.         FPrintf(file, "\n");
  1531.     }
  1532. }
  1533.  
  1534. /*
  1535.  *        ParseStartupOpts()
  1536.  *
  1537.  *        Handles the startup options, either on the command line or via
  1538.  *        the tooltypes, and sets the default options accordingly.
  1539.  *
  1540.  *        We handle a couple of options specially (LOCALE and SETTINGS) since
  1541.  *        these must be set before doing anything else at all (we can't even
  1542.  *        print a meaningful error message without LOCALE, for example.)
  1543.  *
  1544.  *        After those, we read in our configuration file from disk, and then
  1545.  *        parse the remaining items which can thus override any of the options
  1546.  *        specified in the config file. This applies even to tooltypes, so if
  1547.  *        an icon has a certain option hardcoded into it, this will always
  1548.  *        override a config file with the same option set.
  1549.  *
  1550.  *        Normally, CLI and Tooltype options are only used to control things
  1551.  *        like opening a default logfile, set the Commodity priority or config
  1552.  *        file name, making SnoopDos start in the background, or automatically
  1553.  *        opening one or more windows.
  1554.  *
  1555.  *        As a final step, if we spot that we are not the main instance of
  1556.  *        SnoopDos, we send all the new commands to the background copy instead.
  1557.  *         We also signal the background copy to come to the foreground by
  1558.  *        default (Workbench) or if no other options are specified (CLI).
  1559.  *
  1560.  *        Returns TRUE for success, FALSE for failure.
  1561.  *
  1562.  */
  1563. int ParseStartupOpts(int argc, char **argv)
  1564. {
  1565.     struct Settings newset = DefaultSettings;
  1566.     struct DiskObject *IconCache[20];
  1567.     struct DiskObject *dobj = NULL;
  1568.     struct WBArg *wbarg;
  1569.     char msg[200];
  1570.     int success = 1;
  1571.     int maxargs;
  1572.     int i;
  1573.     int gotsettings = 0;        /* If true, settings keyword specified */
  1574.  
  1575.     /*
  1576.      *        We start off in a special disabled state (not 0, not 1)
  1577.      *        to ensure no events get monitored during our initialisation.
  1578.      *        We use a special state so that we can detect if the user
  1579.      *        specifies Disabled = Yes/No during startup.
  1580.      */
  1581.     Disabled = 2;        /* Start up in disabled state */
  1582.  
  1583.     if (WBenchMsg) {
  1584.         /*
  1585.          *        Starting up from Workbench.
  1586.          */
  1587.         if (!IconBase)
  1588.             return (FALSE);
  1589.  
  1590.         maxargs = min(WBenchMsg->sm_NumArgs, 20);
  1591.  
  1592.         for (i = 0, wbarg = WBenchMsg->sm_ArgList; i < maxargs; i++, wbarg++) {
  1593.             BPTR olddir;
  1594.  
  1595.             IconCache[i] = NULL;
  1596.             if (wbarg->wa_Lock && *wbarg->wa_Name) {
  1597.                 olddir = CurrentDir(wbarg->wa_Lock);
  1598.                 dobj   = GetDiskObject(wbarg->wa_Name);
  1599.                 if (dobj) {
  1600.                     char *param;
  1601.                     
  1602.                     param = FindToolType(dobj->do_ToolTypes,
  1603.                                          CmdNames[CMD_SETTINGS]);
  1604.                     if (param && *param) {
  1605.                         strcpy(DefaultConfigName, param);
  1606.                         gotsettings = 1;
  1607.                     }
  1608.                     param = FindToolType(dobj->do_ToolTypes,
  1609.                                          CmdNames[CMD_LANGUAGE]);
  1610.                     if (param && *param)
  1611.                         strcpy(Language, param);
  1612.  
  1613.                     param = FindToolType(dobj->do_ToolTypes,
  1614.                                          CmdNames[CMD_PATCHRAMLIB]);
  1615.                     if (param && stricmp(param, "no") == 0)
  1616.                         NoPatchRamLib = 1;
  1617.  
  1618.                     IconCache[i] = dobj;
  1619.                 }
  1620.                 CurrentDir(olddir);
  1621.             }
  1622.         }
  1623.     } else {
  1624.         /*
  1625.          *        Starting up from the CLI so scan the command line using
  1626.          *        the passed-in arguments.
  1627.          */
  1628.         if (argc > 1) {
  1629.             if (argv[1][0] == '-' || argv[1][0] == '?') {
  1630.                 Printf(MSG(MSG_CLI_USAGE), CommodityTitle, argv[0]);
  1631.                 return (FALSE);
  1632.             }
  1633.         }
  1634.  
  1635.         /*
  1636.          *        Do a prescan of the command line looking
  1637.          *        for SETTINGS, LANGUAGE or PATCHRAMLIB, keywords.
  1638.          */
  1639.         for (i = 1; i < argc; i++) {
  1640.             char cmdname[50];
  1641.             char param[150];
  1642.             char newcmd[200];
  1643.             int boolvalue;
  1644.             struct Command *cmd;
  1645.             int cid;
  1646.  
  1647.             cid = ParseCommand(argv[i], cmdname, param, &boolvalue, &cmd);
  1648.             if (cid == CMD_NOPARAM && ((i + 1) < argc)) {
  1649.                 /*
  1650.                  *        Indicates we didn't get enough parameters for our
  1651.                  *        command. Let's grab the next option off the command
  1652.                  *        line instead and see if that makes sense.
  1653.                  */
  1654.                 mysprintf(newcmd, "%s %s", argv[i], argv[i+1]);
  1655.                 cid = ParseCommand(newcmd, cmdname, param, &boolvalue, &cmd);
  1656.                 i++;    /* Skip over next parameter */
  1657.             }
  1658.             switch (cid) {
  1659.                 case CMD_SETTINGS:
  1660.                     strcpy(DefaultConfigName, param);
  1661.                     gotsettings = 1;
  1662.                     break;
  1663.  
  1664.                 case CMD_LANGUAGE:
  1665.                     strcpy(Language, param);
  1666.                     break;
  1667.  
  1668.                 case CMD_PATCHRAMLIB:
  1669.                     NoPatchRamLib = !boolvalue;
  1670.                     break;
  1671.             }
  1672.         }
  1673.     }
  1674.  
  1675.     /*
  1676.      *        Now initialise locale according to the language chosen,
  1677.      *        and read in our default configuration file.
  1678.      */
  1679.     InitLocale(Language);
  1680.     InitMenus();
  1681.     /*
  1682.      *        Note that LoadConfig() and further ExecCommand() calls may
  1683.      *        cause the settings to be installed at any time, and UpdateFlags
  1684.      *        to be reset to null. Thus, it is important to ensure that
  1685.      *        we initialise them correctly in the first place.
  1686.      */
  1687.     UpdateFlags = SET_ALL;
  1688.     if (SnoopPort) {
  1689.         /*
  1690.          *        We only initialise our patches if we're the only task
  1691.          *        running at the moment. We leave the initialisation
  1692.          *        until now so that we can control whether or not our
  1693.          *        ramlib patch gets installed.
  1694.          */
  1695.         if (!InitPatches()) {
  1696.             if (WBenchMsg)
  1697.                 ShowError(MSG(MSG_ERROR_INITPATCHES));
  1698.             else
  1699.                 Printf("%s\n", MSG(MSG_ERROR_INITPATCHES));
  1700.             Cleanup(40);
  1701.         }
  1702.         if (!gotsettings) {
  1703.             /*
  1704.              *        If we haven't yet got a settings file, then try a number of
  1705.              *        possible locations (in order of priority). If we find a
  1706.              *        match, we overwrite the default config name with the new
  1707.              *        name, for future use by LoadConfig and SaveConfig.
  1708.              */
  1709.             static char *defconfig[] = {
  1710.                 "PROGDIR:" SETTINGS_BASENAME,
  1711.                 "S:"       SETTINGS_BASENAME,
  1712.                 "ENVARC:"  SETTINGS_BASENAME,
  1713.                 NULL
  1714.             };
  1715.             APTR oldwinptr = *TaskWindowPtr;
  1716.             char **pdefname;
  1717.  
  1718.             *TaskWindowPtr = (APTR)-1;
  1719.             for (pdefname = defconfig; *pdefname; pdefname++) {
  1720.                 BPTR lk = Lock(*pdefname, ACCESS_READ);
  1721.  
  1722.                 if (lk) {
  1723.                     UnLock(lk);
  1724.                     break;
  1725.                 }
  1726.             }
  1727.             if (!*pdefname) {
  1728.                 /*
  1729.                  *        Choose a good default name. We try for ENVARC:
  1730.                  *        initially, but if that fails, fall back on S:
  1731.                  */
  1732.                 if (IsFileSystem(defconfig[2]))
  1733.                     pdefname = &defconfig[2];
  1734.                 else
  1735.                     pdefname = &defconfig[1];
  1736.             }
  1737.             strcpy(DefaultConfigName, *pdefname);
  1738.             strcpy(ConfigFileName,      *pdefname);
  1739.             *TaskWindowPtr = oldwinptr;
  1740.         } else {
  1741.             /*
  1742.              *        Do a quick check to see if the filename specified
  1743.              *        using the Settings keyword exists -- if it doesn't,
  1744.              *        then don't bother to try loading it (this avoids
  1745.              *        a requester being shown unnecessarily).
  1746.              */
  1747.             BPTR lk = Lock(DefaultConfigName, ACCESS_READ);
  1748.  
  1749.             if (lk)
  1750.                 UnLock(lk);
  1751.             else
  1752.                 gotsettings = 0;
  1753.         }
  1754.  
  1755.         /*
  1756.          *        Now, one way or another, we have the default config filename
  1757.          *        set up so try and load it.
  1758.          */
  1759.         if (!LoadConfig(DefaultConfigName,
  1760.                         (WBenchMsg ? MODE_TOOLTYPE : MODE_CMDLINE), &newset)
  1761.             && gotsettings)
  1762.         {
  1763.             ShowError(MSG(MSG_ERROR_LOADING_SETTINGS), DefaultConfigName);
  1764.         }
  1765.     }
  1766.  
  1767.     /*
  1768.      *        Finally, lets parse the remaining startup options and/or icons
  1769.      */
  1770.     if (WBenchMsg) {
  1771.         /*
  1772.          *        Scan all the config files (if any) that were passed as
  1773.          *        parameters via icons.
  1774.          */
  1775.         wbarg = WBenchMsg->sm_ArgList + 1;
  1776.         for (i = 1; i < WBenchMsg->sm_NumArgs; i++, wbarg++) {
  1777.             char *name = wbarg->wa_Name;
  1778.  
  1779.             if (SnoopPort) {
  1780.                 BPTR olddir = CurrentDir(wbarg->wa_Lock);
  1781.  
  1782.                 LoadConfig(name, MODE_INTERNAL, &newset);
  1783.                 CurrentDir(olddir);
  1784.             } else {
  1785.                 /*
  1786.                  *        There's a background copy running so we need
  1787.                  *        to tell it to load the config file instead.
  1788.                  */
  1789.                 char *p;
  1790.  
  1791.                 mysprintf(msg, "%s ", CmdNames[CMD_LOADSETTINGS]);
  1792.                 p = msg + strlen(msg);
  1793.                 NameFromLock(wbarg->wa_Lock, p, 150);
  1794.                 AddPart(p, wbarg->wa_Name, 150);
  1795.                 SendRemote(msg, MODE_TOOLTYPE);
  1796.             }
  1797.         }
  1798.  
  1799.         /*
  1800.          *        Rescan the icons, this time processing all the tooltypes that
  1801.          *        we recognise.  Any we don't recognise are ignored. SETTINGS
  1802.          *        command may get parsed a second time, but that's okay.
  1803.          */
  1804.         for (i = 0; i < maxargs; i++) {
  1805.             dobj = IconCache[i];
  1806.             if (dobj) {
  1807.                 char **tooltypes;
  1808.  
  1809.                 for (tooltypes = dobj->do_ToolTypes; *tooltypes; tooltypes++) {
  1810.                     if (SnoopPort)
  1811.                         ExecCommand(*tooltypes, MODE_TOOLTYPE, &newset);
  1812.                     else
  1813.                         SendRemote(*tooltypes, MODE_TOOLTYPE);
  1814.                 }
  1815.                 FreeDiskObject(dobj);
  1816.             }
  1817.         }
  1818.         if (!SnoopPort)
  1819.             SendRemote(CmdNames[CMD_SHOW], MODE_CMDLINE);
  1820.     } else {
  1821.         /*
  1822.          *        Do a proper scan of the CLI arguments.
  1823.          */
  1824.         for (i = 1; i < argc; i++) {
  1825.             char newcmd[200];
  1826.             char *thiscmd = argv[i];
  1827.             struct Command *cmd;
  1828.             int boolvalue;
  1829.             int cid;
  1830.  
  1831.             /*
  1832.              *        Check if the command we're checking needs more than
  1833.              *        one parameter. If so, and if it wasn't supplied, we
  1834.              *        assume that the parameter after it on the command
  1835.              *        line is to be used. This means the user doesn't have
  1836.              *        to specifically type the '='.
  1837.              *
  1838.              *        HELP is a special case, since HELP will work with zero
  1839.              *        parameters too. We only try and handle help if there
  1840.              *        is at least one more parameter after it on the command
  1841.              *        line. If there isn't, then we print a list of supported
  1842.              *        commands instead.
  1843.              */
  1844.             cid = ParseCommand(thiscmd, newcmd, newcmd+50, &boolvalue, &cmd);
  1845.             if ( (i+1) < argc && (cid == CMD_HELP ||
  1846.                                   (cid == CMD_NOPARAM && cmd->numparms > 0)) )
  1847.             {
  1848.                 /*
  1849.                  *        We didn't have a parameter for this command, so
  1850.                  *        assume the next parameter on the command line is
  1851.                  *        the parameter instead.
  1852.                  */
  1853.                 mysprintf(newcmd, "%s %s", argv[i], argv[i+1]);
  1854.                 thiscmd = newcmd;
  1855.                 i++;
  1856.             } else if (cid == CMD_HELP) {
  1857.                 /*
  1858.                  *        Didn't have anything following the HELP so
  1859.                  *        print CLI help instead and exit immediately.
  1860.                  */
  1861.                 ShowCommands(Output());
  1862.                 return (0);
  1863.             }
  1864.             if (SnoopPort) {
  1865.                 switch (ExecCommand(thiscmd, MODE_CMDLINE, &newset)) {
  1866.                     case EXEC_FAIL:
  1867.                         Printf(MSG(MSG_ERROR_CLI_FAILED), thiscmd);
  1868.                         success = 0;
  1869.                         break;
  1870.  
  1871.                     case EXEC_NOPARAM:
  1872.                         Printf(MSG(MSG_ERROR_CLI_NOPARAM), thiscmd);
  1873.                         success = 0;
  1874.                         break;
  1875.  
  1876.                     case EXEC_UNKNOWN:
  1877.                         Printf(MSG(MSG_ERROR_CLI_UNKNOWN), thiscmd);
  1878.                         success = 0;
  1879.                         break;
  1880.  
  1881.                     // case EXEC_OKAY:
  1882.                 }
  1883.             } else {
  1884.                 SendRemote(thiscmd, MODE_CMDLINE);
  1885.             }
  1886.         }
  1887.         if (!SnoopPort && argc == 1)
  1888.             SendRemote(CmdNames[CMD_SHOW], MODE_CMDLINE);
  1889.     }
  1890.     if (!SnoopPort)
  1891.         success = 0;
  1892.  
  1893.     /*
  1894.      *        Now check if the user specified Disable=YES (or NO) during
  1895.      *        startup. If they didn't, then reset the disable flag.
  1896.      *        Regardless, we want to update the function flags to reflect
  1897.      *        the current disable state.
  1898.      */
  1899.     if (Disabled == 2)
  1900.         SetMonitorMode(MONITOR_NORMAL);
  1901.  
  1902.     if (success)
  1903.         InstallSettings(&newset, UpdateFlags | SET_FUNC);
  1904.  
  1905.     return (success);
  1906. }
  1907.